package def;

import java.util.ArrayList;
import java.util.Collections;
import java.util.StringTokenizer;

public class Event extends Argument {
	public String tid = null;
	public String eid = null;
	public EventType eventType = null; 
	public ArrayList<Argument> args = new ArrayList< Argument>();
	public ArrayList<ArgType> types = new ArrayList< ArgType>();
	public Event(){

	}

	public String toString(){
		StringBuilder sb = new StringBuilder();
		sb.append("[Event]");
		//T-span of trigger

		// Event 
		sb.append(eid+"\t"+eventType+":");
		if (getTspan()!=null){
			sb.append("{"+getTspan()+"}");
		}
		else{
			sb.append("{tspan=null}");
		}
		// TODO: put theme in the beginning
		// TODO: add THEME2
		sb.append(" [");
		for (int i = 0; i < args.size();i++){
			if (args.get(i)!=null)
				sb.append(" "+types.get(i)+":"+args.get(i).getId() +"::"+ args.get(i).getTspan());
			else{
				sb.append(" "+types.get(i)+":null");
			}
		}
		sb.append("]");
		//		sb.append("\n");
		return sb.toString();
	}

	@Override
	public String getId() {
		return eid;
	}

	/**
	 * always merge event with tspan to another without tspan
	 * @param event
	 * @return
	 */
	public boolean merge(Event event){

		if (this.getTspan() == null)
		{
			if (event.getTspan()!=null){
				if (event.getTspan().tid .equals( this.tid)){
					this.setTspan(event.getTspan());
					return true;
				}
				else{
					return false;
				}
			}
			else{
				System.err.println("Event.merge to two events. neither has tspan.");
			}
		}
		else{
			if (event.getTspan() != null)
				return event.merge(this);
			else{
				System.err.println("Event.merge to two events. neither has tspan.");
			}
		}
		return false;
	}

	@Override
	public void parseLine(String line) {
		StringTokenizer st = new StringTokenizer(line);
		eid = st.nextToken();
		// nextToken returns "Protein" all the time
		String[] pair = st.nextToken().split(":");
		eventType = EventType.valueOf(pair[0]);
		tid = pair[1];
		while (st.hasMoreTokens()){
			pair = st.nextToken().split(":");
			types.add(ArgType.valueOf(pair[0]));
			Argument role = Argument.find(pair[1]);
			if (role == null)
			{
				if (pair[1].startsWith("T")){
					role = new Protein();
					((Protein)role).pid = pair[1];
					//					role.tspan = new TSpan();
					//					role.tspan.tid = pair[1];
					//					role.tspan.textType = TextType.valueOf("Protein");
					//					Argument.argsInDoc.put(pair[1], role);
				}
				else if (pair[1].startsWith("E")){
					role = new Event();
					((Event)role).eid = pair[1];
				}
				else{
					System.err.println("adding unknown elements");
				}
			}
			args.add(role);
		}
	}

	/**
	 * see if this object fit a ground truth one.
	 */
	public boolean fit(Object o){
		if (o instanceof Event){
			Event e = (Event) o;
			boolean correct = true;
			if (this.eventType.equals(e.eventType) &&
					e.getTspan().text.contains(this.getTspan().text)){
				for (int i = 0; i < types.size(); i++){
					// TODO!
				}
				return correct;
			}
			else{
				return false;
			}
		}else 
			return false;
	}
	@Override public boolean equals(Object obj){
		if (obj instanceof Event){
			Event e = (Event) obj;
			int match = 0;
			if (args.size()== e.args.size()){
				for (int i = 0; i < args.size(); i++){
					for (int j = 0; j < e.args.size(); j++){
						// equals or ==? FIXME
						if (args.get(i)==(e.args.get(j))){
							if (types.get(i) ==  ArgType.Theme || types.get(i) ==  ArgType.Theme2 || types.get(i) ==  ArgType.Theme3 || types.get(i) ==  ArgType.Theme4){
								if (e.types.get(i) ==  ArgType.Theme || e.types.get(i) ==  ArgType.Theme2 || e.types.get(i) ==  ArgType.Theme3 || e.types.get(i) ==  ArgType.Theme4){
									match++;
									break;
								}
							}
							else{
								if (types.get(i).equals(e.types.get(j))){
									match++;
									break;
								}
							}
						}
					}
				}
			}
			else{
				match = -1;
			}
			if (match!=args.size()){
				return false;
			}
			else{
				return true;
			}
		}
		else{
			return false;
		}
	}
	/*@Override public int hashCode(){
		int c = 0;
		for (int i = 0; i < args.size(); i++){
			c+= args.get(i).tspan.hashCode()+types.get(i).hashCode();
		}
		return c;
	}*/

	public boolean hasChild(Event e){
		return hasChild(e, new ArrayList<Event>());  

	}
	private boolean hasChild(Event e, ArrayList<Event> visited){
		boolean has = false;
		if (e== this)
			return true;
		for (Event v: visited){
			if (this == v)
				// already has a loop
				return false;
		}
		visited.add(this);
		for (int i = 0; i < args.size(); i++){
			if (args.get(i) instanceof Event)
				has = ((Event)args.get(i)).hasChild(e, visited);
			if (has)
				break;
		}		
		return has;
	}
}
